package com.ark.frigate.redis.lock.aspect;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;

import com.ark.frigate.redis.RedisLockService;
import com.ark.frigate.redis.lock.ManageAspect;
import com.ark.frigate.redis.lock.annotaion.LockManage;

import lombok.extern.slf4j.Slf4j;

/**
 * LockAop
 *
 * @author zengweilong
 */
@Slf4j
@Aspect
public class LockManageAspect extends ManageAspect {

    @Autowired
    private RedisLockService redisLockService;

    @Around("@annotation(lockManage)")
    public Object executeBefore(ProceedingJoinPoint pjp, LockManage lockManage) throws Throwable {

        LockResult lockResult = new LockResult();
        lockResult.setLockManage(lockManage);
        lockResult.setLockKey(getLockKey(pjp, lockManage));
        try {
            //获取redis lock
            checkLock(lockResult);
            //执行方法
            Object value = pjp.proceed();
            return value;
        } finally {
            if (lockResult.isFlag()) {
                unLock(lockResult);
            }
        }
    }

    private void checkLock(LockResult lockResult) {
        int timeout = lockResult.getLockManage().timeout();
        boolean lock = redisLockService.lock(lockResult.getLockKey(), lockResult.lockKey, timeout);
        if (!lock) {
            throw new RuntimeException("你请求太快，请稍后再试.");
        }
        lockResult.setFlag(true);
    }

    private String getLockKey(ProceedingJoinPoint pjp, LockManage lockManage) {

        String lockKey = lockManage.key();
        Object[] argsArray = pjp.getArgs();
        if (null != argsArray) {
            int[] args = lockManage.args();
            lockKey += getKey(argsArray, args);
        }

        //拼key
        if (StringUtils.isBlank(lockManage.key())) {
            lockKey = getKey("LOCK:", pjp, lockKey);
        } else {
            lockKey = "LOCK:" + lockKey;
        }

        return lockKey;
    }

    private LockResult unLock(LockResult lockResult) {
        if (lockResult.getLockManage().autoRelease()) {
            log.info("释放Redis锁:{}", lockResult.getLockKey());
            redisLockService.del(lockResult.getLockKey());
            lockResult.setFlag(false);
        }
        return lockResult;
    }

    class LockResult {

        private LockManage lockManage;

        private boolean flag = false;

        private String lockKey = "";

        public LockManage getLockManage() {
            return lockManage;
        }

        public void setLockManage(LockManage lockManage) {
            this.lockManage = lockManage;
        }

        public String getLockKey() {
            return lockKey;
        }

        public void setLockKey(String lockKey) {
            this.lockKey = lockKey;
        }

        public boolean isFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }

    }
}
